/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.formserver.viewmodel.common;

import com.inspur.edp.bef.bizentity.GspBizEntityElement;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bef.bizentity.operation.BizMgrAction;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection;
import com.inspur.edp.cef.designtime.api.collection.GspEnumValueCollection;
import com.inspur.edp.cef.designtime.api.collection.GspFieldCollection;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.designtime.api.element.GspEnumValue;
import com.inspur.edp.cef.designtime.api.entity.CustomizationInfo;
import com.inspur.edp.cef.designtime.api.entity.DynamicPropSetInfo;
import com.inspur.edp.cef.designtime.api.util.MetadataUtil;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.DotNetToJavaStringHelper;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import com.inspur.edp.formserver.viewmodel.action.IViewModelParameterCollection;
import com.inspur.edp.formserver.viewmodel.action.MappedBizAction;
import com.inspur.edp.formserver.viewmodel.action.ViewModelAction;
import com.inspur.edp.formserver.viewmodel.action.ViewModelActionType;
import com.inspur.edp.formserver.viewmodel.action.mappedbiz.MappedBizActionParameter;
import com.inspur.edp.formserver.viewmodel.action.mappedbiz.MappedBizActionParameterCollection;
import com.inspur.edp.formserver.viewmodel.action.viewmodelbase.ViewModelReturnValue;
import com.inspur.edp.formserver.viewmodel.collection.VMActionCollection;
import com.inspur.edp.formserver.viewmodel.collection.ViewObjectCollection;
import com.inspur.edp.formserver.viewmodel.common.mapping.GspVoElementMapping;
import com.inspur.edp.formserver.viewmodel.common.mapping.GspVoElementSourceType;
import com.inspur.edp.formserver.viewmodel.common.mapping.GspVoObjectSourceType;
import com.inspur.edp.formserver.viewmodel.exception.ViewModelException;
import com.inspur.edp.formserver.viewmodel.exception.VoModelErrorCodes;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.api.entity.uri.MetadataURI;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.metadata.rtcustomization.api.CustomizationService;
import io.iec.edp.caf.commons.utils.CollectionUtils;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * The Tool Of Link Business Entity By View Model
 *
 * @author Benjamin Gong
 * @version 2021/1/11 17:13
 */
public class LinkBeUtils {
    private final static CustomizationService SERVICE = SpringBeanUtils.getBean(CustomizationService.class);
    private boolean isRuntime;
    private GspMetadata metadata;
    private boolean isExtend;

    public LinkBeUtils() {

    }

    public LinkBeUtils(boolean isRuntime) {
        this.isRuntime = isRuntime;
    }

    public GspMetadata getMetadata() {
        return metadata;
    }

    public void setMetadata(GspMetadata metadata) {
        this.metadata = metadata;
    }

    public boolean isExtend() {
        return isExtend;
    }

    public void setIsExtend(boolean extend) {
        this.isExtend = extend;
    }

    private final java.util.HashMap<String, GspBusinessEntity> bizEntitiesDic = new java.util.HashMap<String,
            GspBusinessEntity>();
    private RefCommonService lcmDtService;

    public RefCommonService getLcmDtService() {
        if (lcmDtService == null)
            lcmDtService = SpringBeanUtils.getBean(RefCommonService.class);
        return lcmDtService;
    }

    private CustomizationService customizationService;

    public CustomizationService getCustomizationService() {
        if (customizationService == null)
            customizationService = SpringBeanUtils.getBean(CustomizationService.class);
        return customizationService;
    }

    private String errorToken = "#GspBefError# ";
    /**
     * key 扩展vo上基础字段mapping记录的be元数据id
     * value 扩展vo对应的扩展be元数据id
     */
    private final Map<String, String> metadataIdDic = new HashMap<>();

    public final void linkWithBe(GspViewModel vm) {
        if (vm.getMainObject().getMapping() == null || vm.getMainObject().getMapping().getSourceType() != GspVoObjectSourceType.BeObject) {
            return;
        }
        // 联动前清空缓存
        metadataIdDic.clear();
        bizEntitiesDic.clear();
        // ① 对象
        linkMainObj(vm, vm.getMainObject());
        // ② 操作
        linkActions(vm);
        // 带出字段为枚举时，赋值枚举信息
        linkBeRefElements(vm);
    }

    /**
     * 关联带出字段联动
     *
     * @param vm
     */
    public final void linkBeRefElements(GspViewModel vm) {
        ArrayList<IGspCommonElement> eles = vm.getAllElementList(true);
        for (IGspCommonElement ele : eles) {
            if (ele.getIsVirtual() || !ele.getIsRefElement()) {
                continue;
            }
            GspViewModelElement viewEle = (GspViewModelElement) ele;
            if (viewEle.getMapping() == null) {
                throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1012, null, vm.getName(), vm.getCode(), viewEle.getName());
            }
            if (viewEle.getMapping().getSourceType() != GspVoElementSourceType.BeElement) {
                continue;
            }
            if (viewEle.getParentAssociation() == null) {
                throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1013, null, vm.getName(), vm.getCode(), viewEle.getName());
            }
            GspViewObject viewObject = (GspViewObject) viewEle.getBelongObject();
            GspBizEntityElement bizEle = getRefBizElement(vm, viewObject, viewEle, viewEle.getParentAssociation().getRefModelID(), viewEle.getRefElementId(), true);
            if (bizEle == null) {
                throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1014, null, vm.getName(), vm.getID(), viewEle.getName(), viewEle.getCode(), viewEle.getID(), viewEle.getRefElementId(),
                        viewEle.getParentAssociation().getRefModelName(), viewEle.getParentAssociation().getRefModelCode(), viewEle.getParentAssociation().getRefModelID());
            }
            // udt
            viewEle.setIsUdt(bizEle.getIsUdt());
            viewEle.setUdtID(bizEle.getUdtID());
            viewEle.setUdtName(bizEle.getUdtName());
            viewEle.setUdtPkgName(bizEle.getUdtPkgName());
            if (!ele.getIsRefElement() || ele.getObjectType() != GspElementObjectType.Enum) {
                continue;
            }

            if (bizEle.getObjectType() != GspElementObjectType.Enum) {
                throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1015, null, viewEle.getName(), viewEle.getCode());
            }
            // 赋值枚举信息
            viewEle.setContainEnumValues(bizEle.getContainEnumValues());

        }
    }


    //#region 对象

    public void linkMainObj(GspViewObject viewObj) {
        // 虚拟对象无映射bizObj
        if (viewObj == null || viewObj.getIsVirtual()) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1016, null);
        }
        GspBizEntityObject bizObject = getBizObject(viewObj.getMapping(), viewObj.getCode());
        if (bizObject == null) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1017, null);
        }

        linkBizObject(viewObj, bizObject);
    }

    public void linkMainObj(GspViewModel viewModel, GspViewObject viewObj) {
        // 虚拟对象无映射bizObj
        if (viewObj == null || viewObj.getIsVirtual()) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1016, null);
        }
        GspBizEntityObject bizObject = getBizObject(viewModel, viewObj, viewObj.getMapping(), viewObj.getCode());
        if (bizObject == null) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1017, null);
        }

        linkBizObject(viewModel, viewObj, bizObject);
    }

    public void linkBizObject(GspViewObject viewObj, GspBizEntityObject bizObject) {
        // ① 基本信息
        linkObjectBasicInfo(viewObj, bizObject);
        // ② 字段集合
        linkElements(viewObj);
        // ③ 字段相关属性
        linkObjectSelfInfo(viewObj, bizObject, viewObj.getParentObject() == null ? null : viewObj.getParentObject().getIDElement().getID());
        // ④ 子对象集合
        if (viewObj.getContainChildObjects() != null && viewObj.getContainChildObjects().size() != 0) {
            ViewObjectCollection childObjList = viewObj.getContainChildObjects();
            Iterator<IGspCommonObject> iterators = childObjList.iterator();
            while (iterators.hasNext()) {
                GspViewObject childObj = (GspViewObject) iterators.next();
                if (childObj.getIsVirtual()) {
                    continue;
                }
                GspBizEntityObject childBizObject = getBizObject(childObj.getMapping(), childObj.getCode());
                if (childBizObject == null) {
                    iterators.remove();
                    continue;
                }
                linkBizObject(childObj, childBizObject);
            }
        }
    }

    public void linkBizObject(GspViewModel viewModel, GspViewObject viewObj, GspBizEntityObject bizObject) {
        // ① 基本信息
        linkObjectBasicInfo(viewObj, bizObject);
        // ② 字段集合
        linkElements(viewModel, viewObj);
        // ③ 字段相关属性
        linkObjectSelfInfo(viewObj, bizObject, viewObj.getParentObject() == null ? null : viewObj.getParentObject().getIDElement().getID());
        // ④ 子对象集合
        if (viewObj.getContainChildObjects() != null && viewObj.getContainChildObjects().size() != 0) {
            ViewObjectCollection childObjList = viewObj.getContainChildObjects();
            Iterator<IGspCommonObject> iterators = childObjList.iterator();
            while (iterators.hasNext()) {
                GspViewObject childObj = (GspViewObject) iterators.next();
                if (childObj.getIsVirtual()) {
                    continue;
                }
                GspBizEntityObject childBizObject = getBizObject(viewModel, childObj, childObj.getMapping(), childObj.getCode());
                if (childBizObject == null) {
                    iterators.remove();
                    continue;
                }
                linkBizObject(viewModel, childObj, childBizObject);
            }
        }
    }

    public void linkObjectBasicInfo(GspViewObject viewObj, GspBizEntityObject bizObject) {
        // 若vo节点未修改，则联动be节点编号
        if (DotNetToJavaStringHelper.isNullOrEmpty(viewObj.getCode())) {
            viewObj.setCode(bizObject.getCode());
        }
    }

    public void linkObjectSelfInfo(GspViewObject viewObj, GspBizEntityObject bizObject, String parentObjectElementId) {
        ArrayList<IGspCommonField> elementList = viewObj.getContainElements().getAllItems(item -> item.getIsVirtual() == false);
        HashMap<String, IGspCommonField> viewElements = new HashMap<>();
        for (IGspCommonField item : elementList) {
            viewElements.put(item.getID(), item);
        }
        // 字段mapping字典
        java.util.HashMap<String, String> elementMappings = ConvertUtils.getElementMappingsDic(elementList);

        // ② 分级信息
//        ConvertUtils.UpdateHirarchyInfo(bizObject, viewObj, elementMappings, viewElements);
        // ③ 时间戳相关
//        ConvertUtils.UpdateTimeStampElements(bizObject, viewObj, elementMappings);
        // ④ID生成规则
        ConvertUtils.updateColumnGenerateId(bizObject, viewObj, elementMappings);
        // ⑤唯一性约束
//		ConvertUtils.updateContainConstraints(bizObject, viewObj, elementMappings, viewElements);
        //// ⑥关联信息-vo多源后，主子表关联不需要联动
        //ConvertUtils.UpdateViewObjectKeys(bizObject, viewObj, parentObjectElementId);
    }

    //#endregion

    //#region 字段

    public void linkElements(GspViewObject viewObj) {
        ArrayList<IGspCommonField> elementList = viewObj.getContainElements().getAllItems(item -> !item.getIsVirtual());

        // 字段mapping字典
        if (CollectionUtils.isEmpty(elementList)) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1018, null, viewObj.getName());
        }
        for (IGspCommonField ele : elementList) {
            GspViewModelElement viewEle = (GspViewModelElement) ele;
            if (viewEle != null) {
                GspBizEntityElement bizElement = getBizElement(viewEle.getMapping(), viewEle.getLabelID());
                if (bizElement == null) {
                    viewObj.getContainElements().remove(ele);
                    continue;
                }
                linkBizElement(viewEle, bizElement);
                // 兼容旧版mapping的be映射字段
                if (DotNetToJavaStringHelper.isNullOrEmpty(viewEle.getMapping().getTargetElementId())) {
                    viewEle.getMapping().setTargetElementId(bizElement.getID());
                }
                if (DotNetToJavaStringHelper.isNullOrEmpty(viewEle.getMapping().getTargetObjectId()) || !viewEle.getMapping().getTargetObjectId().equals(bizElement.getBelongObject().getID())) {
                    viewEle.getMapping().setTargetObjectId(bizElement.getBelongObject().getID());
                }
            }
        }
    }

    public void linkElements(GspViewModel viewModel, GspViewObject viewObj) {
        ArrayList<IGspCommonField> elementList = viewObj.getContainElements().getAllItems(item -> item.getIsVirtual() == false);

        // 字段mapping字典
        if (CollectionUtils.isEmpty(elementList)) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1018, null,
                    viewModel.getCode(), viewModel.getName(), viewObj.getCode(), viewObj.getName());
        }
        for (IGspCommonField ele : elementList) {

            GspViewModelElement viewEle = (GspViewModelElement) ele;
            if (viewEle != null) {
                GspBizEntityElement bizElement = getBizElement(viewModel, viewObj, viewEle, viewEle.getMapping(), viewEle.getLabelID());
                if (bizElement == null) {
                    viewObj.getContainElements().remove(ele);
                    continue;
                }
                linkBizElement(viewEle, bizElement);
                // 兼容旧版mapping的be映射字段
                if (DotNetToJavaStringHelper.isNullOrEmpty(viewEle.getMapping().getTargetElementId())) {
                    viewEle.getMapping().setTargetElementId(bizElement.getID());
                }
                if (DotNetToJavaStringHelper.isNullOrEmpty(viewEle.getMapping().getTargetObjectId()) || !viewEle.getMapping().getTargetObjectId().equals(bizElement.getBelongObject().getID())) {
                    viewEle.getMapping().setTargetObjectId(bizElement.getBelongObject().getID());
                }
            }
        }
    }

    public void linkBizElement(GspViewModelElement viewEle, GspBizEntityElement bizEle) {
        linkElementBasicInfo(viewEle, bizEle);
        linkElementObjectType(viewEle, bizEle);
    }

    public void linkElementBasicInfo(GspViewModelElement ele, GspBizEntityElement bizElement) {
        boolean canEditLengthAndPrecision = true;
//		ele.setBillCodeConfig(bizElement.getBillCodeConfig().clone());
        if (ele.getMDataType() != bizElement.getMDataType()) {
            ele.setMDataType(bizElement.getMDataType());
            canEditLengthAndPrecision = false;
        }
        ele.setIsMultiLanguage(bizElement.getIsMultiLanguage());

        if (bizElement.getIsRequire()) {
            ele.setIsRequire(bizElement.getIsRequire());
        }
        if (bizElement.getReadonly()) {
            ele.setReadonly(bizElement.getReadonly());
        }

        // udt相关
        ele.setIsUdt(bizElement.getIsUdt());
        ele.setUdtID(bizElement.getUdtID());
        ele.setUdtName(bizElement.getUdtName());
        ele.setUdtPkgName(bizElement.getUdtPkgName());

        GspFieldCollection beChildEles = bizElement.getChildElements();
        GspFieldCollection voChildEles = ele.getChildElements();
        if (beChildEles.size() != voChildEles.size()) {
            voChildEles.clear();
            for (IGspCommonField beChildEle : beChildEles) {
                GspViewModelElement viewModelElement = ConvertUtils.toElement(
                        (IGspCommonElement) beChildEle,
                        ele.getMapping().getTargetMetadataPkgName(),
                        ele.getMapping().getTargetMetadataId(),
                        GspVoElementSourceType.BeElement);
                voChildEles.add(viewModelElement);
            }
        }

        if (bizElement.getIsUdt()) {
            canEditLengthAndPrecision = false;
        } else {
            canEditLengthAndPrecision = true;
        }

        // 长度精度
        linkLengthAndPrecision(ele, bizElement, canEditLengthAndPrecision);


    }

    /**
     * 更新字段长度精度
     *
     * @param ele
     * @param bizElement
     * @param canEdit
     */
    public void linkLengthAndPrecision(GspViewModelElement ele, GspBizEntityElement bizElement, boolean canEdit) {
        if (canEdit) {
            // 长度精度不可大于be字段
            if (ele.getLength() > bizElement.getLength()) {
                ele.setLength(bizElement.getLength());
            }
            if (ele.getPrecision() > bizElement.getPrecision()) {
                ele.setPrecision(bizElement.getPrecision());
            }
        } else {
            ele.setLength(bizElement.getLength());
            ele.setPrecision(bizElement.getPrecision());
        }
    }

    public void linkElementObjectType(GspViewModelElement ele, GspBizEntityElement bizElement) {
        GspViewModelElement transEle = ConvertUtils.toElement(bizElement, null, ele.getMapping().getTargetMetadataId(), GspVoElementSourceType.BeElement);
        ele.setObjectType(bizElement.getObjectType());
        ele.setEnumIndexType(bizElement.getEnumIndexType());
        switch (bizElement.getObjectType()) {
            case Association:
                if (bizElement.getIsRefElement()) {
                    break;
                }
                linkElementAssos(ele, transEle);
                break;
            case Enum:
                linkElementEnums(ele, transEle);
                break;
            case None:
                break;
            case DynamicProp:
                ele.setDynamicPropSetInfo(bizElement.getDynamicPropSetInfo());
                break;
            default:
                throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1019, null, bizElement.getObjectType().toString());
        }
        if (ele.getObjectType() != GspElementObjectType.Association) {
            ele.getChildAssociations().clear();
        }
        if (ele.getObjectType() != GspElementObjectType.Enum) {
            ele.getContainEnumValues().clear();
        }
        if (ele.getObjectType() != GspElementObjectType.DynamicProp) {
            ele.setDynamicPropSetInfo(new DynamicPropSetInfo());
        }

    }

    public void linkElementEnums(GspViewModelElement ele, GspViewModelElement transElement) {
        GspEnumValueCollection voEnumValues = ele.getContainEnumValues().clone();
        ele.getContainEnumValues().clear();

        for (GspEnumValue enumItem : transElement.getContainEnumValues()) {
            GspEnumValue enumValue = enumItem.clone();
            if (!CollectionUtils.isEmpty(voEnumValues)) {
                for (GspEnumValue voEnumValue : voEnumValues) {
                    if (voEnumValue.getValue().equals(enumValue.getValue())) {
                        enumValue.setI18nResourceInfoPrefix(voEnumValue.getI18nResourceInfoPrefix());
                    }
                }
            }
            ele.getContainEnumValues().add(enumValue);
        }
    }

    public void linkElementAssos(GspViewModelElement ele, GspViewModelElement transElement) {
        GspAssociationCollection currentAssos = ele.getChildAssociations().clone(ele);
        if (ele.getChildAssociations() != null && ele.getChildAssociations().size() > 0) {
            ele.getChildAssociations().clear();
        }
        if (transElement.getChildAssociations() == null || transElement.getChildAssociations().size() == 0) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1020, null, ele.getCode(), ele.getName());
        }
        // 目前策略：关联信息全部带出
        // 若关联模型未改变，则关联只处理带出字段
        for (GspAssociation transAssociation : transElement.getChildAssociations()) {
            transAssociation.setBelongElement(ele);
            GspAssociation currentAsso = getAssociation(currentAssos, transAssociation.getId());
            if (currentAsso != null && currentAsso.getRefModelID().equals(transAssociation.getRefModelID())) {
                handleRefElementCollection(transAssociation, currentAsso);
                ele.getChildAssociations().add(currentAsso);
            } else {
                ele.getChildAssociations().add(transAssociation);
            }
        }

    }

    /**
     * 处理已删掉的be关联带出字段
     *
     * @param transAssociation
     * @param currentAsso
     */
    public void handleRefElementCollection(GspAssociation transAssociation, GspAssociation currentAsso) {
        GspFieldCollection originVoRefElements = currentAsso.getRefElementCollection().clone(currentAsso.getRefElementCollection().getParentObject(), currentAsso);
        currentAsso.getRefElementCollection().clear();
        GspFieldCollection transRefElements = transAssociation.getRefElementCollection();
        for (IGspCommonField refEle : originVoRefElements) {
            GspViewModelElement transRefElement = (GspViewModelElement) transRefElements.getItem(ele -> ele.getRefElementId().equals(refEle.getRefElementId()));
            if (transRefElement == null) {
                continue;
            }
            // 兼容旧的带出字段mapping中无TargetElementID及TargetObjectID问题
            handleEleMapping(transRefElement.getMapping(), ((GspViewModelElement) refEle).getMapping());
            refEle.setIsFromAssoUdt(transRefElement.getIsFromAssoUdt());
            currentAsso.getRefElementCollection().add(refEle);
        }
    }

    public void handleEleMapping(GspVoElementMapping transMapping, GspVoElementMapping eleMapping) {
        // 兼容旧的带出字段mapping中无TargetElementID及TargetObjectID问题
        if (DotNetToJavaStringHelper.isNullOrEmpty(eleMapping.getTargetObjectId())) {
            eleMapping.setTargetObjectId(transMapping.getTargetObjectId());
        }
        if (DotNetToJavaStringHelper.isNullOrEmpty(eleMapping.getTargetElementId())) {
            eleMapping.setTargetElementId(transMapping.getTargetElementId());
        }
        // 若关联带出字段ID已更新
        if (!eleMapping.getTargetElementId().equals(transMapping.getTargetElementId())) {
            eleMapping.setTargetElementId(transMapping.getTargetElementId());
            eleMapping.setTargetObjId(transMapping.getTargetObjId());
        }
    }

    public GspAssociation getAssociation(GspAssociationCollection collection, String associationId) {
        return (GspAssociation) collection.getItem(item -> associationId.equals(item.getId()));
    }

    public GspViewModelElement getElement(GspFieldCollection collection, String labelId) {
        for (IGspCommonField item : collection) {
            if (labelId.equals(item.getLabelID())) {
                return (GspViewModelElement) ((GspViewModelElement) item != null ? item : null);
            }
        }
        return null;
    }
    //#endregion

    //#region 操作

    public void linkActions(GspViewModel vm) {
        ArrayList<ViewModelAction> list = vm.getActions().getAllItems(item -> item.getType() == ViewModelActionType.BEAction);
        VMActionCollection mappedBeActions = new VMActionCollection();
        mappedBeActions.addAll(list);
        GspBusinessEntity be = null;
        be = getBizEntity(vm, vm.getMapping().getTargetMetadataId());
        if (mappedBeActions.size() > 0) {
            for (ViewModelAction voAction : mappedBeActions) {
                ViewModelMapping mapping = voAction.getMapping();
                if (mapping == null || mapping.getTargetObjId() == null || "".equals(mapping.getTargetObjId()))
                    continue;
                String actionId = mapping.getTargetObjId();
                BizMgrAction mgrAction = (BizMgrAction) be.getBizMgrActions().getItem(item -> actionId.equals(item.getID()));
                if (mgrAction == null) {
                    vm.getActions().remove(voAction);
                    continue;
                }
                MappedBizAction beAction = ConvertUtils.toMappedAction(mgrAction, voAction.getMapping().getTargetMetadataId(), null);
                linkWithMgrAction(voAction, beAction);
            }
        }
    }

    public void linkWithMgrAction(ViewModelAction voAction, MappedBizAction beAction) {
        voAction.setCode(beAction.getCode());
        voAction.setName(beAction.getName());
        linkParameters(voAction, beAction);
        linkReturnValue(voAction, beAction);
//		targetAction.getParameterCollection().clear();
//		if (sourceAction.getParameterCollection().getCount() > 0)
//			for (int i = 0; i < sourceAction.getParameterCollection().getCount(); i++) {
//				targetAction.getParameterCollection().add(sourceAction.getParameterCollection().getItem(i));
//			}
//
//		targetAction.setReturnValue(sourceAction.getReturnValue());
    }

    /**
     * vo上联动be的参数
     * @param voAction
     * @param beAction
     */
    private void linkParameters(ViewModelAction voAction, MappedBizAction beAction) {
        //vo上的业务实体映射操作参数列表
        IViewModelParameterCollection voParams = voAction.getParameterCollection();
        //be上的动作参数列表
        IViewModelParameterCollection beParams = beAction.getParameterCollection();
        //如果be上的参数为空， be上把参数都去掉了，此时vo上的参数需要直接清空
        if (beParams.getCount()==0) {
            voParams.clear();
            return;
        }
        //1、vo上的动作参数和be上的动作参数个数保持一致
        //2、vo上的动作参数比be上的动作参数少  be上新增参数
        if (voParams.getCount()<=beParams.getCount()) {
            linkAddedParameter(beParams,voParams);
            return;
        }
        //3、vo上的动作参数比be上的动作参数多 be上删除了参数
        linkDeletedParameter(beParams,voParams);
    }

    /**
     * 处理be上删除参数以及修改参数编号的场景
     * @param beParams be动作参数集合
     * @param voParams vo动作参数集合
     */
    private void linkDeletedParameter(IViewModelParameterCollection beParams, IViewModelParameterCollection voParams) {
        //构造map集合，be和vo上的动作参数编号有哪些保持一致
        Map<String,String> usedParamDic=new HashMap<>();
        for (int i = 0; i < voParams.getCount(); i++) {
            MappedBizActionParameter voParam = (MappedBizActionParameter) voParams.getItem(i);
            MappedBizActionParameter beParam = (MappedBizActionParameter) beParams.stream().
                    filter(item -> voParam.getParamCode().equals(((MappedBizActionParameter) item).getParamCode())).
                    findFirst().orElse(null);
            if (beParam!=null) {
                //vo和be动作参数编号一致的参数
                usedParamDic.put(voParam.getParamCode(), voParam.getID());
            }
        }
        //vo上的动作参数编号和be上的动作参数编号，完全不一致了，be上修改了所有参数的编号
        //usedParamDic个数为0时，be上修改了所有动作参数的编号，默认按照vo上的参数顺序，重新赋值id
        if (usedParamDic.size()==0){
            for (int i = 0; i < voParams.getCount(); i++) {
                MappedBizActionParameter voParam = (MappedBizActionParameter) voParams.getItem(i);
                MappedBizActionParameter beParam = (MappedBizActionParameter) beParams.getItem(i);
                if (beParam!=null) {
                    beParam.setID(voParam.getID());
                }
            }
            voParams.clear();
            voParams.addAll(beParams);
            return;
        }
        //vo上的动作参数编号和be上的动作参数编号一致的，按照vo上动作参数编号对应的id赋值
        //vo上的部分动作参数编号和be上的动作参数编号不一致的， be上修改了部分参数的编号,此时按照be上的动作参数id赋值
        for (int i = 0; i < beParams.getCount(); i++) {
            MappedBizActionParameter beParam = (MappedBizActionParameter) beParams.getItem(i);
            if (usedParamDic.containsKey(beParam.getParamCode()))
                beParam.setID(usedParamDic.get(beParam.getParamCode()));
        }
        voParams.clear();
        voParams.addAll(beParams);
    }

    /**
     * 处理参数个数一致修改参数编号以及新增参数的场景
     * @param beParams be动作参数集合
     * @param voParams vo动作参数集合
     */
    private void linkAddedParameter(IViewModelParameterCollection beParams, IViewModelParameterCollection voParams) {
        IViewModelParameterCollection newVoParams=new MappedBizActionParameterCollection();
        for (int i = 0; i < beParams.getCount(); i++) {
            MappedBizActionParameter beParam = (MappedBizActionParameter) beParams.getItem(i);
            MappedBizActionParameter voParam = (MappedBizActionParameter) voParams.getItem(i);
            //be上新增的动作参数，vo上添加新参数
            if (voParam == null) {
                newVoParams.add(beParam);
            } else {
                //参数个数一致的情况，回写vo上的原动作参数id
                beParam.setID(voParam.getID());
                newVoParams.add(beParam);
            }
        }
        voParams.clear();
        voParams.addAll(newVoParams);
    }

    private void linkReturnValue(ViewModelAction targetAction, MappedBizAction sourceAction) {
        ViewModelReturnValue returnValue = sourceAction.getReturnValue();
        //重新赋值ID
        returnValue.setID(targetAction.getReturnValue().getID());
        targetAction.setReturnValue(returnValue);
    }

    public GspBusinessEntity getBe(String id) {
        return getBizEntity(id);
    }

    public GspBizEntityElement getRefBizElement(String refBeId, String refElementId) {
        return getRefBizElement(refBeId, refElementId, true);
    }

    public GspBizEntityElement getRefBizElement(String refBeId, String refElementId, boolean containRef) {
        GspBusinessEntity be = getBizEntity(refBeId);
        ArrayList<IGspCommonElement> list = be.getAllElementList(true);
        for (IGspCommonElement ele : list) {
            if (refElementId.equals(ele.getID())) {
                return (GspBizEntityElement) ele;
            }
        }
        return null;
    }

    public GspBizEntityElement getRefBizElement(GspViewModel viewModel, GspViewObject viewObject, GspViewModelElement voEle, String refBeId, String refElementId, boolean containRef) {
        GspBusinessEntity be = null;
        be = getBizEntity(viewModel, refBeId);
        ArrayList<IGspCommonElement> list = be.getAllElementList(true);
        for (IGspCommonElement ele : list) {
            if (refElementId.equals(ele.getID())) {
                return (GspBizEntityElement) ele;
            }
        }
        return null;
    }

    @Deprecated
    public GspBizEntityElement getBizElement(ViewModelMapping mapping) {
        return getBizElement(mapping, "");
    }

    @Deprecated
    public GspBizEntityElement getBizElement(ViewModelMapping mapping, String elementLabelId) {
        if (mapping == null) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1021, null, elementLabelId);
        }
        String metadataId = mapping.getTargetMetadataId();
        String objId = mapping.getTargetObjId();
        GspBizEntityElement ele = getRefBizElement(metadataId, objId, false);
        return ele;
    }

    /**
     * 根据vo字段获取对应的be字段信息
     *
     * @param viewModel
     * @param viewObject
     * @param voEle
     * @param mapping
     * @param elementLabelId
     * @return
     */
    public GspBizEntityElement getBizElement(GspViewModel viewModel, GspViewObject viewObject, GspViewModelElement voEle, ViewModelMapping mapping, String elementLabelId) {
        if (mapping == null) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1021, null, elementLabelId);
        }
        String metadataId = mapping.getTargetMetadataId();
        CustomizationInfo customizationInfo = voEle.getCustomizationInfo();
        // 运行时定制扩展VO上的基础字段Mapping信息记录的BEID是基础BEID,可能是引入的其他的BE元数据ID,扩展VO模型Mapping记录的是扩展BEID；
        // 是扩展VO时，字段长度修改以后，后续的字段联动根据基础BE上的字段长度处理，此时会有问题，此处的metadataId需要重新获取
        if (isExtend && !(customizationInfo != null && customizationInfo.isCustomized())) {
            metadataId = getMetadataIdByRelation(viewModel, metadataId);
        }
        String objId = mapping.getTargetObjId();
        GspBizEntityElement ele = getRefBizElement(viewModel, viewObject, voEle, metadataId, objId, false);
        return ele;
    }

    /**
     * /**
     * 根据扩展VO元数据、基础VO字段记录的BE元数据ID获取扩展BE元数据ID
     *
     * @param viewModel  扩展VO元数据
     * @param metadataId 基础VO字段记录的BE元数据ID，metadataId的值可能是创建当前VO对应的BE元数据ID，也可能是引入其他字段对应的BE元数据ID
     * @return
     */
    private String getMetadataIdByRelation(GspViewModel viewModel, String metadataId) {
        //缓存中获取扩展BE元数据ID
        // metadataIdDic字典的key 扩展vo上基础字段mapping记录的be元数据id
        // metadataIdDic字典的value 扩展vo对应的扩展be元数据id
        if (metadataIdDic.containsKey(metadataId))
            return metadataIdDic.get(metadataId);
        //当前扩展VO元数据对应的BE元数据ID
        String beId = viewModel.getMapping().getTargetMetadataId();
        //基础VO字段mapping记录的BE元数据ID和扩展VO元数据对应的BE元数据ID一致时处理
        if (beId.equals(metadataId)) {
            metadataIdDic.put(metadataId, beId);
            return metadataId;
        }
        //根据扩展BE元数据ID获取基础BE元数据
        GspMetadata basicMetadataByExtMdId = SERVICE.getBasicMetadataByExtMdId(beId, "");
        if (basicMetadataByExtMdId == null) {
            metadataIdDic.put(metadataId, metadataId);
            return metadataId;
        }
        //基础BE元数据ID
        String basicBeId = basicMetadataByExtMdId.getHeader().getId();
        //通过扩展BE获取基础的BE元数据ID，通过扩展关系获取基础VO字段记录的基础BE元数据ID
        //基础VO字段mapping记录的BE元数据ID和扩展VO元数据对应的BE元数据ID不一致，和basicBeId一致时处理
        if (basicBeId.equals(metadataId)) {
            metadataIdDic.put(metadataId, beId);
            return beId;
        }
        //VO上引入其他字段对应的BE元数据ID在扩展表单中不处理，直接返回本身
        metadataIdDic.put(metadataId, metadataId);
        return metadataId;
    }

    public GspBizEntityObject getBizObject(ViewModelMapping mapping, String objCode) {
        if (mapping == null) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1022, null, objCode);
        }
        String metadataId = mapping.getTargetMetadataId();
        String objId = mapping.getTargetObjId();
        GspBusinessEntity be = getBizEntity(metadataId);
        GspBizEntityObject bizObj = (GspBizEntityObject) be.getNode(node -> node.getID().equals(objId));
        return bizObj;
    }

    public GspBizEntityObject getBizObject(GspViewModel viewModel, GspViewObject viewObject, ViewModelMapping mapping, String objCode) {
        if (mapping == null) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1022, null, objCode);
        }
        String metadataId = mapping.getTargetMetadataId();
        String objId = mapping.getTargetObjId();
        GspBusinessEntity be = null;
        be = getBizEntity(viewModel, metadataId);
        GspBizEntityObject bizObj = (GspBizEntityObject) be.getNode(node -> node.getID().equals(objId));
        return bizObj;
    }

    //todo:依赖lcm加载元数据服务
    public GspBusinessEntity getBizEntity(String id) {
        if (bizEntitiesDic.containsKey(id)) {
            return bizEntitiesDic.get(id);
        }
        GspMetadata metadata;
        if (isRuntime) {
            //运行时获取，元数据不带有i8n信息
            metadata = MetadataUtil.getCustomMetadataByI18n(id, false);
        } else {
            //设计时获取
            metadata = getLcmDtService().getRefMetadata(id);
        }
        //todo 需要后续讨论，抛异常时提示出明确的元数据信息，不仅仅提示id
        if (metadata == null) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1023, null, id);
        }
        GspBusinessEntity entity = (GspBusinessEntity) metadata.getContent();
        bizEntitiesDic.put(id, entity);
        return entity;
    }

    public GspBusinessEntity getBizEntity(GspViewModel viewModel, String id) {
        if (bizEntitiesDic.containsKey(id)) {
            return bizEntitiesDic.get(id);
        }
        GspMetadata metadata;
        if (isRuntime) {
            //运行时获取，元数据不带有i8n信息
            metadata = MetadataUtil.getCustomMetadataByI18n(id, false);
        } else {
            //设计时获取
            MetadataURI targetURI = new MetadataURI();
            targetURI.setId(id);
            setMetadataURI(targetURI, getMetadata(), id);

            MetadataURI sourceURI = new MetadataURI();
            setSourceMetadataURI(sourceURI, getMetadata());
            metadata = getLcmDtService().getRefMetadata(targetURI, sourceURI, "");
        }
        if (metadata == null) {
            String vmNameSpace = getVmNameSpace(getMetadata());
            MetadataHeader metadataHeader = getgetDependentMetadataInfo(getMetadata(), id);
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1024, null, viewModel.getCode(), viewModel.getName(), vmNameSpace, id, metadataHeader.getCode(),
                    metadataHeader.getName(), metadataHeader.getNameSpace());
        }
        GspBusinessEntity entity = (GspBusinessEntity) metadata.getContent();
        bizEntitiesDic.put(id, entity);
        return entity;
    }

    private MetadataHeader getgetDependentMetadataInfo(GspMetadata metadata, String id) {
        MetadataHeader metadataHeader = new MetadataHeader() {{
            setName("");
            setCode("");
            setNameSpace("");
        }};
        if (metadata == null || metadata.getRefs() == null || metadata.getRefs().size() == 0) {
            return metadataHeader;
        }
        MetadataReference ref = ViewModelActionUtil.getReference(metadata.getRefs(), id);
        if (ref == null || ref.getDependentMetadata() == null) {
            return metadataHeader;
        }
        return ref.getDependentMetadata();
    }

    private String getVmNameSpace(GspMetadata sourceMeta) {
        if (sourceMeta == null || sourceMeta.getHeader() == null)
            return "";
        return sourceMeta.getHeader().getNameSpace();
    }

    private void setMetadataURI(MetadataURI metadataURI, GspMetadata metadata, String id) {
        if (metadata == null || metadata.getRefs() == null || metadata.getRefs().size() == 0) {
            return;
        }
        MetadataReference ref = ViewModelActionUtil.getReference(metadata.getRefs(), id);
        if (ref == null || ref.getDependentMetadata() == null) {
            return;
        }
        metadataURI.setCode(ref.getDependentMetadata().getCode());
        metadataURI.setNameSpace(ref.getDependentMetadata().getNameSpace());
        metadataURI.setType(ref.getDependentMetadata().getType());
        return;
    }
    private void setSourceMetadataURI(MetadataURI metadataURI, GspMetadata metadata) {
        if (metadata == null || metadata.getHeader() == null) {
            return;
        }
        metadataURI.setCode(metadata.getHeader().getCode());
        metadataURI.setNameSpace(metadata.getHeader().getNameSpace());
        metadataURI.setType(metadata.getHeader().getType());
        return;
    }

}